package com.ssy.jt808.gateway.domain.converter;

import com.ssy.gaea.leaf.id.IdGenerator;
import com.ssy.gaea.leaf.id.StandaloneSnowflakeId;
import com.ssy.gaea.util.JsonMapper;
import com.ssy.jt808.gateway.infrastructure.constant.Jt808Constant;
import com.ssy.jt808.gateway.sdk.terminal.constant.location.LocationAdditionInfoEnum;
import com.ssy.jt808.gateway.sdk.terminal.constant.location.LocationAlarmBitConstant;
import com.ssy.jt808.gateway.sdk.terminal.constant.location.LocationAlarmEnum;
import com.ssy.jt808.gateway.sdk.terminal.constant.location.addition.InOutAreaDirectionEnum;
import com.ssy.jt808.gateway.sdk.terminal.constant.location.addition.InOutAreaEnum;
import com.ssy.jt808.gateway.sdk.terminal.constant.location.addition.OverSpeedAreaEnum;
import com.ssy.jt808.gateway.sdk.terminal.constant.location.addition.RouteDriveTimeResultEnum;
import com.ssy.jt808.gateway.sdk.terminal.pojo.info.LocationInfo;
import com.ssy.jt808.gateway.sdk.terminal.pojo.info.alarm.*;
import com.ssy.jt808.gateway.sdk.terminal.utils.BitUtil;
import com.ssy.jt808.protocol.commons.transform.attribute.*;
import com.ssy.jt808.protocol.t808.T0200;
import org.springframework.util.CollectionUtils;

import java.util.Map;
import java.util.TreeMap;


/**
 * 0x0200 定位附加信息转换器
 *
 * @author wangzezhou
 */
public class LocationDataConverter{


  private static final IdGenerator idGenerator = new StandaloneSnowflakeId();

  public static void extractLocationInfo( T0200 t0200,
                                          LocationInfo locationInfo,
                                          TerminalAlarmInfo terminalAlarmInfo ){

    locationInfo.setId(idGenerator.nextId());
    locationInfo.setTime(t0200.getDeviceTime());
    locationInfo.setLng((float)(t0200.getLongitude()/Jt808Constant.ONE_MILLION));
    locationInfo.setLat((float)(t0200.getLatitude()/Jt808Constant.ONE_MILLION));
    locationInfo.setAltitude(t0200.getAltitude());
    locationInfo.setSpeed((float)(t0200.getSpeed()*0.1));
    locationInfo.setDirection(t0200.getDirection());
    locationInfo.setAlarmBits(t0200.getAlarmBits());
    locationInfo.setStatusBits(t0200.getStatusBits());

    Map<LocationAdditionInfoEnum,Object> additionInfo = new TreeMap<>();

    Map<Integer,Object> additionData = t0200.getAttributes();
    extractLocationAlarmInfo(terminalAlarmInfo, t0200.getAlarmBits(), additionData);
    extractAdditionInfo(terminalAlarmInfo, additionInfo, additionData);
    terminalAlarmInfo.setLocationId(locationInfo.getId());
    terminalAlarmInfo.setLocationTime(locationInfo.getTime());

    locationInfo.setAdditionInfo(JsonMapper.toJsonNode(additionInfo));
  }

  public static void extractLocationAlarmInfo( TerminalAlarmInfo terminalAlarmInfo,
                                               int alarmBits,
                                               Map<Integer,Object> additionData ){
    if( alarmBits == 0 ){
      return;
    }

    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.SOS) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.Sos));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.OVER_SPEED) ){
      LocationAlarmInfo alarmInfo;
      Object v = additionData.get(LocationAdditionInfoEnum.OverSpeedAlarm.id());
      if( v != null ){
        alarmInfo = convertSpeedAlarmInfo((OverSpeedAlarm)v);
      }
      else{
        alarmInfo = new LocationAlarmInfo(LocationAlarmEnum.OverSpeed);
      }
      terminalAlarmInfo.addLocationAlarmInfo(alarmInfo);
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.FATIGUE_DRIVING) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.FatigueDriving));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.DANGER_WARNING) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.DangerWarning));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.GNSS_FAILURE) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.GnssFailure));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.GNSS_ANTENNAE_FAILURE) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.GnssAntennaeFailure));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.GNSS_ANTENNAE_CIRCUIT) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.GnssAntennaeCircuit));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.UNDER_POWERED) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.UnderPowered));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.POWER_DOWN) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.PowerDown));
    }
//    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.DISPLAY_FAILURE) ){
//      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum
//      .DisplayFailure));
//    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.TTS_FAILURE) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.TtsFailure));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.CAMERA_FAILURE) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.CameraFailure));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.TRANSPORT_IC_FAILURE) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.TransportIcFailure));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.OVER_SPEED_WARNING) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.OverSpeedWarning));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.FATIGUE_DRIVING_WARNING) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.FatigueDrivingWarning));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.DRIVING_OVERTIME) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.DrivingOvertime));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.STOP_OVERTIME) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.StopOvertime));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.IN_OUT_AREA) ){
      Object v = additionData.get(LocationAlarmEnum.InOutArea.bit());
      LocationAlarmInfo alarmInfo;
      if( v != null ){
        alarmInfo = convertInOutAreaAlarmInfo(LocationAlarmEnum.InOutArea, (InOutAreaAlarm)v);
      }
      else{
        alarmInfo = new LocationAlarmInfo(LocationAlarmEnum.InOutArea);
      }
      terminalAlarmInfo.addLocationAlarmInfo(alarmInfo);
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.IN_OUT_PATH) ){
      Object v = additionData.get(LocationAdditionInfoEnum.InOutAreaAlarm.id());
      LocationAlarmInfo alarmInfo;
      if( v != null ){
        alarmInfo = convertInOutAreaAlarmInfo(LocationAlarmEnum.InOutPath, (InOutAreaAlarm)v);
      }
      else{
        alarmInfo = new LocationAlarmInfo(LocationAlarmEnum.InOutPath);
      }
      terminalAlarmInfo.addLocationAlarmInfo(alarmInfo);
    }

    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.RouteDriveTimeAlarm) ){
      Object v = additionData.get(LocationAdditionInfoEnum.RouteDriveTimeAlarm.id());
      LocationAlarmInfo alarmInfo;
      if( v != null ){
        alarmInfo = convertInOutAreaAlarmInfo(LocationAlarmEnum.RouteDriveTimeAlarm,
                                              (InOutAreaAlarm)v);
      }
      else{
        alarmInfo = new LocationAlarmInfo(LocationAlarmEnum.RouteDriveTimeAlarm);
      }
      terminalAlarmInfo.addLocationAlarmInfo(alarmInfo);
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.DEVIATION_PATH) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.DeviationPath));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.VSS_FAILURE) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.VssFailure));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.FUEL_CAPACITY_ANOMALY) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.FuelCapacity));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.STEALING) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.Stealing));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.ILLEGAL_START) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.IllegalStart));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.ILLEGAL_DISPLACE) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.IllegalDisplace));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.CRASH_WARNING) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.CrashWarning));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.ROLLOVER_WARNING) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.RolloverWarning));
    }
    if( BitUtil.existFlag(alarmBits, LocationAlarmBitConstant.ILLEGAL_OPEN_DOOR) ){
      terminalAlarmInfo.addLocationAlarmInfo(new LocationAlarmInfo(LocationAlarmEnum.IllegalOpenDoor));
    }
  }

  /**
   * jt 框架的附加信息转换成 jt 网关的附加信息。
   */
  public static void extractAdditionInfo( TerminalAlarmInfo alarmInfo,
                                          Map<LocationAdditionInfoEnum,Object> additionInfo,
                                          Map<Integer,Object> additionData ){

    if( CollectionUtils.isEmpty(additionData) ){
      return;
    }

    additionData.forEach(( k, v )->{
      LocationAdditionInfoEnum idEnum = LocationAdditionInfoEnum.map(k);
      if( idEnum == null ){
        return;
      }

      switch(idEnum){
        case Mileage:
          additionInfo.put(idEnum, ((Number)v).intValue()*0.1);
          break;

        //case Fuel:
        case RecorderSpeed:
          additionInfo.put(idEnum, ((Number)v).shortValue()*0.1);
          break;

        case Signal:
        case AlarmEventId:
        case SignalStrength:
        case GnssCount:
          additionInfo.put(idEnum, v);
          break;
        case AnalogQuantity:{
          additionInfo.put(idEnum, ((Number)v).intValue());
        }
        break;
        case AlarmADAS:{
          AdasAlarmInfo info = AdasAlarmInfoConverter.convertAdasAlarmInfo((AlarmADAS)v);
          alarmInfo.setAdasAlarm(info);
          break;
        }
        case AlarmDSM:{
          DsmAlarmInfo info = DsmAlarmInfoConverter.convertDsmAlarmInfo((AlarmDSM)v);
          alarmInfo.setDsmAlarm(info);
          break;
        }
        case AlarmAd:{
          AdAlarmInfo info = AdAlarmInfoConverter.convertAdAlarmInfo((AlarmAD)v);
          alarmInfo.setAdAlarm(info);
          break;
        }
        default:
          break;
      }
    });

  }

  private static OverSpeedAlarmInfo convertSpeedAlarmInfo( OverSpeedAlarm alarm ){
    OverSpeedAreaEnum areaType = OverSpeedAreaEnum.areaType(alarm.getAreaType());

    OverSpeedAlarmInfo info = new OverSpeedAlarmInfo();
    info.setAreaType(areaType);
    info.setAreaId(alarm.getAreaId());
    return info;
  }

  private static InOutAreaAlarmInfo convertInOutAreaAlarmInfo( LocationAlarmEnum alarmType,
                                                               InOutAreaAlarm alarm ){
    InOutAreaEnum areaType = InOutAreaEnum.areaType(alarm.getAreaType());
    InOutAreaAlarmInfo info = new InOutAreaAlarmInfo(alarmType);
    info.setAreaType(areaType);
    info.setAreaId(alarm.getAreaId());

    info.setDirection(InOutAreaDirectionEnum.map(alarm.getDirection()));
    return info;
  }

  private static RouteDriveTimeAlarmInfo convertRouteDriveTimeAlarmInfo( RouteDriveTimeAlarm alarm ){

    RouteDriveTimeAlarmInfo routeDriveTimeAlarmInfo = new RouteDriveTimeAlarmInfo();
    routeDriveTimeAlarmInfo.setAreaId(alarm.getAreaId());
    routeDriveTimeAlarmInfo.setDriveTime(alarm.getDriveTime());
    routeDriveTimeAlarmInfo.setResult(RouteDriveTimeResultEnum.map(alarm.getResult()));
    return routeDriveTimeAlarmInfo;
  }


}
